package plugins

import (
	"data-transfer/conf"
	"fmt"
	"sync"
)

type (

	// Factory store对象创建工厂
	Factory struct {
		cfg *conf.DbConfig
		dbConn DbConn
	}

	//DbConn 代表mysql的连接Wrapper,代表底层数据库的【逻辑连接】
	DbConn struct {
		dbKind DbKind
		cfg *conf.DbConfig
        DB
		sync.Mutex
		refCnt int //引用计数
	}
)

// NewFactory 返回Factory,可用于创建指定类型的数据存储
func NewFactory(cfg *conf.DbConfig,dbKind DbKind) *Factory {
	return &Factory{
		cfg:cfg,
		dbConn:NewRefCountedDBConn(dbKind,cfg),
	}
}

// NewRefCountedDBConn 创建一个mysql【逻辑】连接对象，使用引用计数来决定何时关闭底层的连接对象
//每次调用get()引用计数增加，每次调用Close()递减
func NewRefCountedDBConn(dbKind DbKind,cfg *conf.DbConfig) DbConn {
	return DbConn{
		dbKind: dbKind,
		cfg:cfg,
	}
}

// Get 返回数据库【逻辑】连接，并增加引用计数
func (c *DbConn) Get()(DB,error) {
	c.Lock()
	defer c.Unlock()
	if c.refCnt == 0 {
		conn,err := NewSQLDB(c.dbKind,c.cfg)
		if err != nil {
			return nil,err
		}
		c.DB = conn
	}
	c.refCnt++
	return c,nil
}

// ForceClose 忽略引用计数，关闭底层连接池
func (c *DbConn) ForceClose() {
	c.Lock()
	defer c.Unlock()
	if c.DB != nil {
		err := c.DB.Close()
		if err != nil {
			fmt.Println("failed to close database connection",err)
		}
	}
	c.refCnt = 0
}

// Close 如果引用数为0，关闭底层连接
func (c *DbConn) Close() error {
	c.Lock()
	defer c.Unlock()
	c.refCnt--
	if c.refCnt == 0 {
		err := c.DB.Close()
		c.DB = nil
		return err
	}
	return nil
}